#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct pocketcube
{
    char front[4];
    char back[4];
    char left[4];
    char right[4];
    char up[4];
    char down[4];
    void (*func)(struct pocketcube *self);
} pocube;

// front:0 back:1 left:2 right:3 up:4 down:5 定义面与面之间关系
char **facerelation(pocube *p, int direction)
{
    static char *relation[6][4];
    relation[0][0] = p->up; relation[0][1] = p->right; relation[0][2] = p->down; relation[0][3] = p->left;
    relation[1][0] = p->up; relation[1][1] = p->left; relation[1][2] = p->down; relation[1][3] = p->right;
    relation[2][0] = p->up; relation[2][1] = p->front; relation[2][2] = p->down; relation[2][3] = p->back;
    relation[3][0] = p->up; relation[3][1] = p->back; relation[3][2] = p->down; relation[3][3] = p->front;
    relation[4][0] = p->back; relation[4][1] = p->right; relation[4][2] = p->front; relation[4][3] = p->left;
    relation[5][0] = p->front; relation[5][1] = p->right; relation[5][2] = p->back; relation[5][3] = p->left;
    return relation[direction];
}

// 初始化
void initpocube(pocube *p, const char front[4], const char back[4], const char left[4], const char right[4], const char up[4], const char down[4])
{
    memcpy(p->front, front, sizeof(p->front));
    memcpy(p->back, back, sizeof(p->back));
    memcpy(p->left, left, sizeof(p->left));
    memcpy(p->right, right, sizeof(p->right));
    memcpy(p->up, up, sizeof(p->up));
    memcpy(p->down, down, sizeof(p->down));
}

// 面的编号，左上开始顺时针
int *rotatepara(int a)
{
    static int array[6][4] = {
        {0, 3, 1, 2}, // 正面
        {2, 1, 3, 0}, // 反面
        {1, 0, 2, 3}, // 左面
        {3, 2, 0, 1}, // 右面
        {1, 2, 3, 0}, // 上面
        {2, 1, 0, 3}, // 下面
    };
    return array[a];
}

//编号转化为旋转方向
char *numtochar(pocube *p, int direction)
{
    switch (direction)
    {
    case 0:
        return p->front;
    case 1:
        return p->back;
    case 2:
        return p->left;
    case 3:
        return p->right;
    case 4:
        return p->up;
    case 5:
        return p->down;
    default:
        return NULL;
    }
}

//旋转基准面的顺时针旋转
char *rotatetrue(pocube *p, int direction)
{
    char *arr = numtochar(p, direction);
    if (arr != NULL)
    {
        char last = arr[3];
        for (int i = 3; i > 0; i--)
        {
            arr[i] = arr[i - 1];
        }
        arr[0] = last;
    }
    return arr;
}

// 逆时针旋转
char *rotatefalse(pocube *p, int direction)
{
    rotatetrue(p, direction);
    rotatetrue(p, direction);
    return rotatetrue(p, direction);
}

//para {0, 3, 1, 2}, // 正面
//adjacent relation[0][0] = p->up; relation[0][1] = p->right; relation[0][2] = p->down; relation[0][3] = p->left;
//旋转基准面邻接的面顺时针旋转
void rotateside(pocube *p, int direction)
{
    char **adjacent = facerelation(p, direction);
    int *para = rotatepara(direction);
    char temp = adjacent[0][para[0]];
    char temp2 = adjacent[0][para[1]];
    
    adjacent[0][para[0]] = adjacent[3][para[3]];
    adjacent[3][para[3]] = adjacent[2][para[2]];
    adjacent[2][para[2]] = adjacent[1][para[1]];
    adjacent[1][para[1]] = temp;

    adjacent[0][para[1]] = adjacent[3][para[0]];
    adjacent[3][para[0]] = adjacent[2][para[3]];
    adjacent[2][para[3]] = adjacent[1][para[2]];
    adjacent[1][para[2]] = temp2;
}

//逆时针旋转基准面邻接的面
void rotatesidefalse(pocube *p, int direction)
{
    rotateside(p, direction);
    rotateside(p, direction);
    rotateside(p, direction);
}

void operation(char* c, pocube *p){
    int i;
        for (i = 0; i < (int)strlen(c); i++)
    {
        switch (c[i])
        {
        case 'F':
            rotatetrue(p, 0);
            rotateside(p, 0);
            break;
        case 'B':
            rotatetrue(p, 1);
            rotateside(p, 1);
            break;
        case 'L':
            rotatetrue(p, 2);
            rotateside(p, 2);
            break;
        case 'R':
            rotatetrue(p, 3);
            rotateside(p, 3);
            break;
        case 'U':
            rotatetrue(p, 4);
            rotateside(p, 4);
            break;
        case 'D':
            rotatetrue(p, 5);
            rotateside(p, 5);
            break;
        case 'f':
            rotatefalse(p, 0);
            rotatesidefalse(p, 0);
            break;
        case 'b':
            rotatefalse(p, 1);
            rotatesidefalse(p, 1);
            break;
        case 'l':
            rotatefalse(p, 2);
            rotatesidefalse(p, 2);
            break;
        case 'r':
            rotatefalse(p, 3);
            rotatesidefalse(p, 3);
            break;
        case 'u':
            rotatefalse(p, 4);
            rotatesidefalse(p, 4);
            break;
        case 'd':
            rotatefalse(p, 5);
            rotatesidefalse(p, 5);
            break;
        default:
            printf("Invalid command: %c\n", c[i]);
            return;
        }
    }
}



int main()
{
    pocube mycube;
    char front[4] = {'R', 'R', 'R', 'R'};
    char back[4] = {'O', 'O', 'O', 'O'};
    char left[4] = {'G', 'G', 'G', 'G'};
    char right[4] = {'B', 'B', 'B', 'B'};
    char up[4] = {'W', 'W', 'W', 'W'};
    char down[4] = {'Y', 'Y', 'Y', 'Y'};
    char c[100];

    initpocube(&mycube, front, back, left, right, up, down);
    printf("Please input a command using 'FBLRUDfblrud':\n(Capital letters represent clockwise, lowercase letters represent counterclockwise)\n");
    scanf("%99s", c);
    operation(c, &mycube);
    printf("      %c      \n  %c       %c  \n%c     %c     %c\n    %c   %c    \n%c           %c\n    %c   %c    \n",
           mycube.up[1], mycube.up[0], mycube.up[2], mycube.front[0], mycube.up[3],
           mycube.right[2], mycube.front[3], mycube.right[3], mycube.front[2], mycube.right[0], mycube.front[1], mycube.right[1]);
    
    system("pause");
    return 0;
}
